EP14. AI 앱용 모델 선택
AI 앱 개발 시 모델·API 를 선정하는 5 가지 객관 기준(AI 비중·속도/출력·도메인 특성·라이선스·API 고급 기능)과 도메인 특화 PPL 평가 절차를 정리합니다.
0. 사전 필수 용어 (선행지식)
- LLM (Large Language Model) — 방대한 텍스트로 사전학습된 거대 언어 모델. 본 문서 전반의 "모델" 은 LLM 을 가리킵니다. 예: GPT 계열, Claude 계열, Gemini 계열, Llama 계열. (본문 §1·3·4 에서 활용)
- API (Application Programming Interface) — 모델을 네트워크로 호출해 결과를 받는 표준 인터페이스. 현대 모델 API 는 단순 추론 외에 파일 업로드·RAG·에이전트·스트리밍을 함께 제공합니다. (본문 §3·4·5 에서 활용)
- RAG (Retrieval-Augmented Generation) — 외부 지식 저장소에서 관련 정보를 검색해 프롬프트에 합쳐 LLM 답변을 생성하는 패턴. 환각·도메인 무지를 줄이는 표준 접근. (본문 §3·5 에서 활용)
- Fine-tuning (튜닝) — 사전학습 모델에 도메인 데이터를 추가 학습해 성능을 끌어올리는 절차. 라이선스가 "튜닝 허용" 이어야 가능. (본문 §3·4 에서 활용)
- PPL (Perplexity, 혼란도) — 모델이 평가셋 텍스트 시퀀스를 얼마나 잘 예측하는지 나타내는 지표. 값이 낮을수록(1 에 가까울수록) 좋고, 높을수록(100+) 헤매는 것. (본문 §4 Step 5·§9 에서 활용)
- Corpus (코퍼스) — 모델 평가·학습에 쓰는 대규모 텍스트 집합. 도메인 특화 PPL 평가의 입력. (본문 §4 Step 5 에서 활용)
📚 선행지식이 부족하면 Hugging Face Course (
https://huggingface.co/learn/llm-course) 의 Chapter 1·2 로 LLM·Transformer 의 기본 동작을 학습하세요.
1. 주제 정의
AI 앱용 모델 선택 은 개발하려는 애플리케이션의 요구사항(AI 비중·속도·도메인·라이선스)에 가장 합치하는 LLM 또는 모델 API 를 선정하는 의사결정 절차입니다. 단순히 "최신·최대 모델 = 최적" 이 아니라, 도메인 특성에 따라 작은 모델이 더 효율적인 경우가 많습니다.
핵심 아이디어: 모델은 도메인·요구사항에 맞춰 고른다. "큰 모델 = 좋은 모델" 가설은 거짓이며, 제한된 입출력 도메인일수록 작은 모델로 고성능을 달성할 수 있습니다.
2. 풀려는 문제
- 문제 1 — 비용 폭증: 단순 분류 같은 가벼운 태스크에 범용 거대 모델을 쓰면 토큰 비용·latency 가 불필요하게 커집니다.
- 문제 2 — 성능 미달: 도메인 특화 태스크(의료 영상, 법률 문서 등)에 범용 모델을 쓰면 도메인 지식 부족으로 환각·오답이 증가합니다.
- 문제 3 — 라이선스 위반: 상용 서비스에 사용 가능한 라이선스인지(오픈소스 vs 오픈 웨이트 vs 상용) 사전 검토 없이 배포하면 법적 리스크가 발생합니다.
- 문제 4 — 백엔드 재구현 낭비: 모델 API 가 이미 제공하는 RAG·에이전트·샌드박스 기능을 자체 구현하면 개발 공수·유지비가 중복으로 발생합니다.
💡 실무 노하우: 작은 모델 + 잘 짜인 프롬프트가 거대 모델 + 빈약한 프롬프트보다 비용 대비 성능이 우월한 경우가 흔합니다. 토큰 비용은 입력·출력 모두에 부과되므로 컨텍스트 다이어트가 가장 즉효 절감 수단입니다.
3. 핵심 개념·구조
모델 선택 의사결정은 다음 5 가지 요소의 곱집합으로 정의됩니다.
- AI 비중 (Dependency) — 앱 전체 알고리즘 중 LLM 의존 비율. 클수록 큰 모델 또는 다중 모델 전략.
- 속도·출력량 (Throughput) — 고속·소출력이면 작은 모델, 지연 허용·다출력이면 큰 모델.
- 도메인 특성 (Domain Shape) — 입출력 모두 범용 / 입력 범용·출력 제한 / 입출력 모두 제한 3 분류.
- 라이선스 (License) — 오픈소스 / 오픈 웨이트 / 상용. 그리고 튜닝 가능성.
- API 기능 (Capability) — 파일/RAG·에이전트 그래프·인터프리터 샌드박스·멀티모달·컨텍스트/메모리·구조적 출력.
┌──────────────────────────────────┐
│ AI 앱용 모델 선택 의사결정 │
└──────────────────────────────────┘
│
┌─────────────────────┼────────────────────┐
▼ ▼ ▼
[1. AI 비중·역할] [2. 속도·출력량] [3. 도메인 특성]
- 의존도 % - 고속/저속 - 입력 범용/제한
- 위임 범위 - 출력량 - 출력 범용/제한
│ │ │
└─────────────────────┼────────────────────┘
▼
[4. 라이선스·튜닝]
- 오픈소스/웨이트/상용
- 튜닝/학습 허용 여부
▼
[5. API 고급 기능]
- RAG·에이전트·샌드박스
- 멀티모달·스트리밍
- 컨텍스트·구조적 출력
▼
┌──────────────────────┐
│ 최종 모델·API 선정 │
└──────────────────────┘
📚 참고: Anthropic 의 Choosing the right model 가이드도 유사한 분류 축(능력·속도·비용)을 권장합니다.
4. 구현 가이드 (Do It Yourself)
시작 전 (Before you begin)
이 섹션을 완료하면 본인 도메인의 후보 모델 1~3 개를 Anthropic·OpenAI·HuggingFace 어느 한쪽으로 호출해 정량 평가(PPL 또는 응답 품질)까지 마칠 수 있습니다.
선수 조건:
- Python 3.10+
- pip install anthropic transformers torch python-dotenv
- API 키 1 개 이상 — ANTHROPIC_API_KEY 환경 변수 (또는 OpenAI/Gemini 키)
- (선택) NVIDIA GPU — 자체 PPL 평가용. RTX 3090 24GB 이상 권장.
소요 시간: 약 30 분.
Step 1 — 의사결정 시트 작성
목표: 5 가지 기준에 본인 앱의 답을 적어 후보 모델 범위를 좁힙니다.
다음 표를 model_selection.md 에 저장합니다.
| 기준 | 본인 앱 답 | 시사점 |
|---|---|---|
| 1. AI 비중 | 예: 핵심 (의존도 80% 이상) | → 큰 모델 또는 다중 모델 |
| 2. 위임 범위 | 예: 좁음 (특정 도메인) | → 작은 특화 모델 가능 |
| 3. 속도/출력량 | 예: 고속·소출력 | → 작은 모델 |
| 4. 도메인 입출력 | 예: 입출력 모두 제한 | → 분류 C 형 (작은 모델 + 고성능) |
| 5. 라이선스 | 예: 상용 배포·튜닝 필요 | → 상용 튜닝 허용 또는 Apache·MIT 오픈 |
이 시트는 이후 단계의 입력입니다. 답을 명시적으로 적어 두지 않으면 의사결정이 흐려집니다.
⚠️ 주의: "AI 비중 = 핵심" 이라고 무조건 거대 모델을 선택하지 마세요. 위임 범위가 좁고 출력이 제한되면 작은 모델이 더 빠르고 싸며 정확합니다.
✅ 확인: Step 1 완료. 5 행 모두 답이 채워졌고 "큰/작은", "오픈/상용", "범용/제한" 결정 키워드가 명시되었습니다.
Step 2 — Anthropic SDK 로 후보 모델 호출
목표: 동일 프롬프트를 모델별로 호출해 응답 품질·latency 를 비교합니다.
다음 코드를 compare_models.py 에 추가합니다.
import os
import time
from anthropic import Anthropic
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
CANDIDATES = [
"claude-opus-4-7",
"claude-sonnet-4-6",
"claude-haiku-4-5-20251001",
]
PROMPT = "다음 문장을 분류하세요. 카테고리는 [장난, 진짜] 중 하나입니다.\n문장: 우리집에 불났어요. 빨리 와주세요."
for model_id in CANDIDATES:
start = time.perf_counter()
response = client.messages.create(
model=model_id,
max_tokens=128,
messages=[{"role": "user", "content": PROMPT}],
)
elapsed_ms = (time.perf_counter() - start) * 1000
text = response.content[0].text
print(f"{model_id}\t{elapsed_ms:.0f}ms\t{text!r}")
이 코드는 3 개 후보 모델을 순차 호출해 응답 시간과 텍스트를 출력합니다. 같은 프롬프트로 평가해야 비교가 의미 있습니다.
⚠️ 주의: API 키는 환경 변수 (
ANTHROPIC_API_KEY) 로 주입하세요. 소스에 박으면git push직후 GitHub 자동 스캐너가 키를 폐기시킵니다.💡 실무 노하우: latency 는 첫 호출이 콜드 스타트로 길어집니다. 평균값을 보려면 동일 호출을 5 회 반복해 중앙값을 취하세요. 또한 토큰 비용은 모델별로 자릿수가 다르므로 (Haiku < Sonnet < Opus)
response.usage를 함께 로깅합니다.📚 참고: Anthropic Python SDK 의 Messages API 가이드 와 Pricing 페이지.
✅ 확인: Step 2 완료. 콘솔에 3 행이 출력되고 각 행이 모델ID\tlatency\t응답 형식인지 확인합니다.
Step 3 — 라이선스·튜닝 가능성 검증
목표: 후보 모델 각각의 라이선스를 확인하고 상용 배포·튜닝 가능 여부를 결정합니다.
다음을 점검합니다.
LICENSE_MATRIX = {
"claude-opus-4-7": {"type": "proprietary", "commercial": True, "fine_tune": False},
"meta-llama/Llama-3.3-70B": {"type": "open_weight", "commercial": True, "fine_tune": True, "note": "Llama Community License"},
"mistralai/Mistral-7B-v0.3": {"type": "open_source", "commercial": True, "fine_tune": True, "note": "Apache 2.0"},
"gpt-oss-120b": {"type": "open_weight", "commercial": True, "fine_tune": True, "note": "Apache 2.0 (오픈 웨이트)"},
}
for model, lic in LICENSE_MATRIX.items():
ok = "OK" if lic["commercial"] else "NO"
print(f"{ok} {model:40s} type={lic['type']:14s} fine_tune={lic['fine_tune']}")
용어 정리: - 오픈 소스 (Open Source) — 모델 가중치 + 학습 코드 + 학습 데이터 공개. 진짜 오픈. - 오픈 웨이트 (Open Weight) — 가중치만 공개. 학습 데이터·과정은 비공개. 실무에서는 이 비중이 큼. - 상용 (Proprietary) — API 만 제공. 가중치 비공개.
⚠️ 주의: "오픈" 단어만 보고 상용 배포가 가능하다고 단정하지 마세요. Llama 의 Community License 는 월 활성 사용자가 일정 수치 이상이면 별도 라이선스가 필요합니다. 실제 라이선스 본문을 읽으세요.
💡 실무 노하우: 상용 API 모델도 일부는 fine-tuning 을 지원합니다. 다만 상용 모델 튜닝은 데이터가 벤더 서버로 업로드되므로 사내 보안 정책과 충돌할 수 있습니다.
✅ 확인: Step 3 완료. 사용 예정 모델의 라이선스 타입·상용 가능·튜닝 가능 3 값이 명확합니다.
Step 4 — API 고급 기능 활용 (구조적 출력)
목표: 백엔드를 직접 구현하지 않고 API 가 기본 제공하는 기능을 호출해 보일러플레이트를 줄입니다.
다음 코드는 Anthropic 의 구조적 출력 (tool use) 으로 분류 결과를 강제 스키마로 받습니다.
import json
from anthropic import Anthropic
client = Anthropic()
tools = [{
"name": "report_classification",
"description": "통화 분류 결과를 반환합니다.",
"input_schema": {
"type": "object",
"properties": {
"category": {"type": "string", "enum": ["진짜", "장난"]},
"confidence": {"type": "number", "minimum": 0, "maximum": 1},
"reason": {"type": "string"},
},
"required": ["category", "confidence", "reason"],
},
}]
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=256,
tools=tools,
tool_choice={"type": "tool", "name": "report_classification"},
messages=[{"role": "user", "content": "통화 원문: 우리집에 불났어요. 빨리 와주세요."}],
)
tool_use = next(b for b in response.content if b.type == "tool_use")
print(json.dumps(tool_use.input, ensure_ascii=False, indent=2))
예상 출력:
{
"category": "진짜",
"confidence": 0.95,
"reason": "위급한 화재 상황을 신고하는 명확한 표현이며 장난 의도가 없습니다."
}
이렇게 받으면 후처리 파서·정규식·재시도 로직이 사라집니다.
💡 실무 노하우: 자체 RAG 파이프라인(파서·스플리터·임베딩·벡터DB·리랭커)을 처음부터 짜기 전에, 사용하려는 모델 API 가 파일 업로드 + RAG 를 기본 제공하는지 먼저 확인하세요(2026-05 기준, OpenAI Assistants·Gemini File API·Anthropic Files API 모두 어떤 형태로든 지원하지만 인덱싱 제어 범위는 벤더별로 다릅니다 — 공식 docs 확인 필요).
📚 참고: Anthropic Tool Use 문서 (
https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/overview).
✅ 확인: Step 4 완료. JSON 스키마를 따른 dict 가 항상 같은 키로 반환됩니다.
Step 5 — 도메인 특화 PPL 평가
목표: 도메인과 일치하는 공개 리더보드가 없을 때 자체 코퍼스로 후보 오픈 웨이트 모델의 PPL 을 측정합니다.
다음 코드를 eval_ppl.py 에 추가합니다.
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
MODEL = "mistralai/Mistral-7B-v0.3"
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
tok = AutoTokenizer.from_pretrained(MODEL)
model = AutoModelForCausalLM.from_pretrained(
MODEL, torch_dtype=torch.float16, device_map=DEVICE
)
model.eval()
with open("domain_corpus.txt", encoding="utf-8") as f:
text = f.read()
enc = tok(text, return_tensors="pt").to(DEVICE)
with torch.no_grad():
out = model(**enc, labels=enc.input_ids)
ppl = torch.exp(out.loss).item()
print(f"PPL = {ppl:.2f} (낮을수록 도메인 적합)")
예상 출력:
PPL = 12.34 (낮을수록 도메인 적합)
같은 domain_corpus.txt 로 후보 모델을 모두 측정하면 PPL 작은 모델이 본인 도메인을 더 잘 압니다.
⚠️ 주의: 코퍼스는 본인 도메인의 실제 문서로 만드세요. 학습 데이터에 포함된 일반 코퍼스(Wikipedia 등)로 평가하면 거의 모든 최신 모델이 비슷한 점수를 내 변별력이 사라집니다.
💡 실무 노하우: PPL 은 예측 난이도 일 뿐 실용 성능 의 완전한 대리지표는 아닙니다. 분류·추론 같은 다운스트림 태스크의 실제 정답률(F1·BLEU·도메인 평가셋 정확도)도 같이 보세요.
📚 참고: Hugging Face 의 Perplexity of fixed-length models 문서.
✅ 확인: Step 5 완료. 후보 모델별 PPL 표가 작성되고 최저 PPL 모델이 후보 1 순위로 정해졌습니다.
5. 적용 사례 (공신력 오픈소스)
다음은 모델 호출·평가·라우팅에 실무에서 표준적으로 채택되는 OSS 들입니다 (모두 GitHub stars 5K 이상 또는 벤더 공식 SDK).
- LangChain (
https://github.com/langchain-ai/langchain) — Python 체이닝 프레임워크.ChatAnthropic/ChatOpenAI같은 벤더 추상화 제공. - LlamaIndex (
https://github.com/run-llama/llama_index) — RAG·인덱싱 특화 프레임워크. - Anthropic Python SDK (
https://github.com/anthropics/anthropic-sdk-python) — Claude 공식 SDK. Messages API + Tool use. - OpenAI Python SDK (
https://github.com/openai/openai-python) — Chat Completions + Responses + Assistants. - HuggingFace Transformers (
https://github.com/huggingface/transformers) — 오픈 웨이트 모델 로컬 추론·평가 표준. - vLLM (
https://github.com/vllm-project/vllm) — 오픈 웨이트 모델 고처리량 서빙. PagedAttention 으로 throughput 최적화. - Ollama (
https://github.com/ollama/ollama) — 로컬 LLM 실행 런타임. 개발기·프로토타입에 편리. - LiteLLM (
https://github.com/BerriAI/litellm) — 100+ 모델 공급자 통합 SDK. 벤더 잠금 회피·라우팅. - Spring AI (
https://github.com/spring-projects/spring-ai) — JVM 진영의 모델 추상화. - LangChain4j (
https://github.com/langchain4j/langchain4j) — Java 용 체이닝·에이전트 프레임워크.
📚 참고: 위 OSS 들은 모두 Apache 2.0 / MIT 또는 벤더 공식 라이선스이며 상용 사용 제약이 가벼운 편입니다. 사용 전 LICENSE 파일을 직접 확인하세요.
💡 실무 노하우: 벤더 SDK 직접 호출은 1 개 벤더 락인. LiteLLM 같은 통합 SDK 는 라우팅·페일오버에 자유롭습니다. 프로젝트 초기에는 SDK 직접 호출로 빠르게 가고, 멀티 벤더 운영 단계가 보이면 LiteLLM/LangChain 의 ChatModel 추상화로 이행하는 패턴이 일반적입니다.
6. 핵심 원리
원리 1 — 입출력 자유도가 모델 크기를 결정: 입력·출력의 가능한 패턴 공간이 클수록(범용) 큰 모델이 필요하고, 작을수록(제한) 작은 모델이 동등 이상의 성능을 냅니다. 강의의 도메인 3 분류(A 완전 범용 / B 범용 입력·제한 출력 / C 제한 입출력) 가 이 원리의 직접적 적용입니다.
원리 2 — 모델 API 는 백엔드를 흡수한다: 현대 모델 API 는 RAG·에이전트 그래프·샌드박스·메모리를 기본 제공하므로 동일 기능을 자체 구현하면 비용·유지보수가 중복됩니다. 백엔드 코드를 적게 쓰는 쪽이 일반적으로 더 안정적입니다.
7. 변형·확장
- 모델 라우팅 (Model Routing) — 입력을 분석해 작은 모델 → 큰 모델로 단계적 escalation. LiteLLM·LangChain Router 로 구현.
- 하이브리드 (Cloud + Local) — 민감 정보는 로컬 Ollama·vLLM, 일반 질의는 클라우드 API. 라우팅 규칙으로 분기.
- 다중 모델 앙상블 (Multi-Model Ensemble) — 후보 N 개 응답을 합산·투표. 비용은 N 배지만 일관성 평가에 유용.
- 스트리밍 vs 배치 — UX 가 중요하면 SSE 스트리밍, 처리량이 중요하면 batch API (OpenAI Batch / Anthropic Message Batches).
8. 다른 도구·접근과의 비교 (3-way)
| 축 | 단일 거대 모델 | Fine-tuning 한 작은 모델 | RAG 만 (모델 변경 없음) |
|---|---|---|---|
| 초기 비용 | 낮음 (API 호출만) | 높음 (학습 GPU + 데이터 가공) | 중간 (벡터DB·인덱싱 인프라) |
| 추론 비용 | 매우 높음 (토큰 단가 ×) | 낮음 (자체 호스팅 가능) | 중간 (검색 + 모델 호출) |
| 도메인 정확도 | 보통 (일반 지식 기반) | 매우 높음 (도메인 학습) | 높음 (검색 컨텍스트 주입) |
| 데이터 갱신 | 매번 프롬프트 | 재학습 필요 | 즉시 (인덱스 추가) |
| 진입 난이도 | 낮음 | 높음 | 중간 |
💡 실무 노하우: "최신 사실" 이 중요하면 RAG, "도메인 스타일·용어" 가 중요하면 fine-tuning, "광범위 추론" 이 중요하면 거대 모델. 셋은 배타적이지 않으며 조합 가능합니다.
9. 한계·트레이드오프
- 환각 (Hallucination) — 큰 모델일수록 그럴듯한 거짓을 생성합니다. 도메인 PPL 평가 + RAG + 출력 검증(structured output) 으로 완화하지만 0 으로는 못 만듭니다.
- 비용·Latency — 거대 모델은 토큰당 단가가 자릿수 단위로 비쌉니다. 라우팅·캐싱·프롬프트 압축을 함께 적용해야 운영 비용이 폭주하지 않습니다.
- 데이터 보안 / 벤더 락인 — 상용 API 는 데이터가 벤더 서버로 흐릅니다. 사내 정책·계약 검토 + 통합 SDK(LiteLLM) 로 락인을 분산.
- PPL 의 함정 — PPL 은 단어 예측 가능성일 뿐 실용 정답률과 동치가 아닙니다. 다운스트림 태스크 평가셋(F1·정확도)을 함께 봐야 합니다.
- 리더보드 신뢰도 — 인기 없는 리더보드는 치팅 가능성이 있고, 상위권 모델들은 점수가 군집을 이루어 변별력이 작습니다.
10. 최신 권장 패턴 (2026-05 기준)
다음 항목은 2026-05 기준 벤더 docs·OSS README 에서 표준으로 권장되는 패턴입니다. 시간 경과에 따라 변동되므로 적용 직전 공식 docs 재확인 권장.
- Structured Output / Tool Use 기본 채택 — 후처리 파서 제거. JSON Schema 검증을 API 단에서 처리.
- Prompt Caching — 시스템 프롬프트·긴 컨텍스트 재사용 시 비용 절감. Anthropic·OpenAI·Gemini 모두 어떤 형태로든 캐싱을 지원합니다(벤더별 세부 정책은 공식 docs 확인).
- 모델별 강점 라우팅 — Haiku (저비용·고속), Sonnet (균형), Opus (난해 추론) 처럼 태스크별 모델 분리.
- MCP (Model Context Protocol) — Anthropic 주도 도구 연결 표준(
https://modelcontextprotocol.io/). 도구 통합의 N×M 폭발을 N+M 으로 줄임. - Inference 최적화 OSS — vLLM·SGLang 등 PagedAttention·Continuous Batching 활용으로 자체 호스팅 처리량을 끌어올림.
- 로컬 모델 1차 처리 + 클라우드 fallback — Ollama 로 로컬에서 1차 응답, 신뢰도 부족 시 클라우드 escalation.
📚 참고: Anthropic 의 Building effective agents 가이드는 "워크플로 + 에이전트" 패턴을 명시적으로 구분해 권장합니다.
11. 메타인지 자기평가
본인 코드/시스템에 본 가이드를 적용할 수 있는지 점검합니다.
Step 1 — 현재 상태 점검
# 현재 코드가 어떤 모델을 어떻게 호출하는지 grep
grep -rn -E "model\s*=\s*['\"]" --include="*.py" .
grep -rn -E "anthropic|openai|google\.genai|transformers" --include="*.py" .
Step 2 — 적용 가능성 평가 - 도메인 5 가지 기준 표를 채울 수 있는가? (Step 1 산출물) - 현재 사용 모델의 라이선스·튜닝 가능 여부를 안다? (Step 3) - 같은 프롬프트로 후보 모델 2 개 이상 응답을 받아 비교한 적이 있는가? (Step 2) - 자체 RAG 를 짜기 전에 모델 API 의 파일/Tool/Structured Output 기능을 먼저 시도했는가? (Step 4)
Step 3 — 점진 적용 1. 가장 비싼 호출(토큰 사용량 Top 1) 1 개를 골라 Haiku/Sonnet 로 다운그레이드 PoC. 2. 응답 품질 회귀가 없으면 본 운영에 라우팅 적용. 회귀가 있으면 원본 모델 유지 + 다른 호출로 이동. 3. 측정 지표(latency·cost·정확도) 를 대시보드로 잡아 두면 의사결정이 가벼워집니다.
본 학습자료는 강의 영상의 5 단계 모델 선택 + PPL 평가 흐름을 공식 SDK 코드와 함께 재구성한 것입니다. 정확한 인용은 원본 영상과 각 OSS 의 공식 매뉴얼을 참고하세요.
클릭하거나 Space를 눌러 뒤집기